using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
using System.Windows.Forms;
using System.Reflection;

namespace Common.Shared.Xml.Serialization {
  public class TreeViewSerializer : IDisposable {
    private XmlDocument baseDoc = null;
    /// <summary>
    /// Initializes a new instance of the <see cref="TreeViewSerializer"/> class.
    /// </summary>
    public TreeViewSerializer ( ) {

    }

    public void Serialize ( Stream stream, TreeView tv ) {
      baseDoc = new XmlDocument ( );
      XmlElement eleRoot = SerializeTree ( tv );
      baseDoc.AppendChild ( eleRoot );
      baseDoc.Save ( stream );
    }

    public TreeView Deserialize ( Stream stream ) {
      return null;
    }

    public virtual bool CanDeserialize ( XmlReader xmlReader ) {
      return true;
    }

    #region IDisposable Members

    public void Dispose ( ) {

    }

    #endregion

    private XmlElement SerializeTree ( TreeView tv ) {
      if ( baseDoc != null ) {
        XmlElement treeElement = baseDoc.CreateElement ( tv.GetType ( ).FullName );
        PropertyInfo[] props = tv.GetType ( ).GetProperties ( BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.SetField | BindingFlags.Instance );
        foreach ( PropertyInfo pi in props ) {

          XmlElement ele = baseDoc.CreateElement ( pi.Name );
          ele.SetAttribute ( "Type", pi.PropertyType.FullName );
          if ( pi.CanRead && pi.CanWrite || pi.PropertyType == typeof ( TreeNodeCollection ) ) {
            object propVal = pi.GetValue ( tv, null );
            if ( propVal != null && propVal.GetType ( ) == typeof ( TreeNodeCollection ) ) {

              foreach ( TreeNode tn in tv.Nodes ) {
                XmlElement tele = SerializeTreeNode ( tn );
                if ( tele != null )
                  ele.AppendChild ( tele );
              }
            } else {
              if ( propVal != null )
                ele.InnerText = ObjectSerializerHelper.SerializeObject(propVal);
            }
            treeElement.AppendChild ( ele );
          }
        }
        return treeElement;
      } else
        return null;
    }

    private XmlElement SerializeTreeNode ( TreeNode tn ) {
      XmlElement baseElement = null;
      if ( baseDoc != null ) {
        baseElement = baseDoc.CreateElement ( tn.GetType ( ).FullName );
        PropertyInfo[] props = tn.GetType ( ).GetProperties ( BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.SetField | BindingFlags.Instance );
        foreach ( PropertyInfo pi in props ) {
          XmlElement ele = baseDoc.CreateElement ( pi.Name );
          ele.SetAttribute ( "Type", pi.PropertyType.FullName );
          if ( pi.CanRead && pi.CanWrite || pi.PropertyType == typeof ( TreeNodeCollection ) ) {
            object propVal = pi.GetValue ( tn, null );
            if ( propVal != null && propVal.GetType ( ) == typeof ( TreeNodeCollection ) ) {
              foreach ( TreeNode xtn in tn.Nodes ) {
                XmlElement tele = SerializeTreeNode ( xtn );
                if ( tele != null )
                  ele.AppendChild ( tele );
              }
            } else {
              if ( propVal != null )
                ele.InnerText = propVal.ToString ( );
            }
            baseElement.AppendChild ( ele );
          }
        }
      }
      return baseElement;
    }
  }
}
